﻿#region License
// Copyright 2010 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows;
using java.io;
using java.util;
using java.util.zip;
using MediaWiki.Common;
using MediaWiki.Office.Packaging;
using Exception = java.lang.Exception;
using File = java.io.File;
using ZipPackage = System.IO.Packaging.Package;

namespace MediaWiki.MediaWikiConverter.Exporter
{
  public class ZipContentGetter : IContentGetter
  {
    private readonly string _temporaryPath;

    public ZipContentGetter(Stream zipFileStream)
    {
      string filename = Path.GetTempFileName();

      using (FileStream file = System.IO.File.OpenWrite(filename))
      {
        CopyStream(zipFileStream, file);
      }

      _temporaryPath = Path.GetTempFileName();

      System.IO.File.Delete(_temporaryPath);
      Directory.CreateDirectory(_temporaryPath);

      // unzip the zip file content to a temporary location
      Extract(filename, _temporaryPath);
    }

    private void Extract(string zipFileName, string destinationPath)
    {
      ZipFile zipfile = new ZipFile(zipFileName);
      List<ZipEntry> zipFiles = GetZipFiles(zipfile);

      foreach (ZipEntry zipFile in zipFiles)
      {
        if (!zipFile.isDirectory())
        {
          InputStream s = zipfile.getInputStream(zipFile);
          try
          {
            Directory.CreateDirectory(destinationPath + "\\" + Path.GetDirectoryName(zipFile.getName()));

            FileOutputStream dest = new FileOutputStream(Path.Combine(destinationPath + "\\" + Path.GetDirectoryName(zipFile.getName()), Path.GetFileName(zipFile.getName())));

            try
            {
              int len = 0;
              sbyte[] buffer = new sbyte[7168];
              while ((len = s.read(buffer)) >= 0)
              {
                dest.write(buffer, 0, len);
              }
            }
            finally
            {
              dest.close();
            }
          }
          finally
          {
            s.close();
          }
        }
      }
    }

    private static List<ZipEntry> GetZipFiles(ZipFile zipfil)
    {
      List<ZipEntry> lstZip = new List<ZipEntry>();
      Enumeration zipEnum = zipfil.entries();
      while (zipEnum.hasMoreElements())
      {
        ZipEntry zip = (ZipEntry)zipEnum.nextElement();
        lstZip.Add(zip);
      }
      return lstZip;
    }

    public static void CopyStream(Stream input, Stream output)
    {
      byte[] buffer = new byte[8 * 1024];
      int len;
      while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
      {
        output.Write(buffer, 0, len);
      }
    }

    public Stream GetContent(string name)
    {
      string contentPath = Path.Combine(_temporaryPath, name);

      if (!System.IO.File.Exists(contentPath))
        throw new Exception("Could not find '{0}'".FormatWith(name));

      return System.IO.File.OpenRead(contentPath);
    }

    public string GetStringContent(string name)
    {
      using (StreamReader sr = new StreamReader(GetContent(name)))
      {
        return sr.ReadToEnd();
      }
    }

    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposing)
      {
        // clean up temporary files
        if (_temporaryPath != null && Directory.Exists(_temporaryPath))
        {
          Directory.Delete(_temporaryPath, true);
        }
      }
    }

    ~ZipContentGetter()
    {
      Dispose(false);
    }
  }
}